﻿using DanMuHelper.Video;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace DanMuHelper.Video
{
    /// <summary>
    /// 协调多个VideoController
    /// </summary>
    public class VideoDirector : MonoBehaviour
    {
        [Serializable]
        private class Mutex
        {
            public BaseMediaPlayer A;
            public BaseMediaPlayer B;

            public Mutex(BaseMediaPlayer a, BaseMediaPlayer b)
            {
                A = a;
                B = b;
            }
        }

        /// <summary>
        /// 互斥播放器
        /// </summary>
        [SerializeField]
        private List<Mutex> _mutexes;

        private bool _isInited;

        private void Start()
        {
            LayzyInit();
        }

        private void OnDestroy()
        {
            if (_mutexes?.Count > 0)
            {
                var controllers = new Dictionary<int, BaseMediaPlayer>(_mutexes.Count);
                foreach (var m in _mutexes)
                {
                    var cid = m.A.GetInstanceID();
                    if (!controllers.ContainsKey(cid))
                    {
                        controllers.Add(cid, m.A);
                    }
                    cid = m.B.GetInstanceID();
                    if (!controllers.ContainsKey(cid))
                    {
                        controllers.Add(cid, m.B);
                    }
                }
                foreach (var c in controllers.Values)
                {
                    c.onVideoWillPlay.RemoveListener(OnWillPlay);
                    c.onVideoPlayComplete.RemoveListener(OnPlayComplete);
                }
            }
        }

        private void LayzyInit()
        {
            if (_isInited)
            {
                return;
            }
            if (_mutexes != null)
            {
                var controllers = new Dictionary<int, BaseMediaPlayer>(_mutexes.Count);
                // 填补空缺, a和b互相添加
                var fixMissing = new List<Mutex>();
                foreach (var m in _mutexes)
                {
                    bool missBA = true;
                    foreach (var n in _mutexes)
                    {
                        if (n.B == m.A && n.A == m.B)
                        {
                            missBA = false;
                            break;
                        }
                    }
                    if (missBA)
                    {
                        fixMissing.Add(new Mutex(m.B, m.A));
                    }
                    var cid = m.A.GetInstanceID();
                    if (!controllers.ContainsKey(cid))
                    {
                        controllers.Add(cid, m.A);
                    }
                    cid = m.B.GetInstanceID();
                    if (!controllers.ContainsKey(cid))
                    {
                        controllers.Add(cid, m.B);
                    }
                }
                if (fixMissing.Count > 0)
                {
                    _mutexes.AddRange(fixMissing);
                }
                foreach (var c in controllers.Values)
                {
                    c.onVideoWillPlay.AddListener(OnWillPlay);
                    c.onVideoPlayComplete.AddListener(OnPlayComplete);
                }
            }
            _isInited = true;
        }

        private void OnWillPlay(BaseMediaPlayer controller, IReadOnlyList<IVideoContext> items, int combo)
        {
            if (_mutexes == null)
                return;
            foreach (var m in _mutexes)
            {
                if (m.A == controller)
                {
                    m.B.AddMutex(controller);
                }
            }
        }

        private void OnPlayComplete(BaseMediaPlayer controller, IReadOnlyList<IVideoContext> items, int combo)
        {
            if (_mutexes == null)
                return;
            foreach (var m in _mutexes)
            {
                if (m.A == controller)
                {
                    m.B.RemoveMutex(controller);
                }
            }
        }

        public void AddMutex(BaseMediaPlayer a, BaseMediaPlayer b)
        {
            if (a == b)
            {
                Debug.LogError("VideoController is same");
                return;
            }
            if (a == null || b == null)
            {
                Debug.LogError("VideoController is null");
                return;
            }
            LayzyInit();
            if (_mutexes == null)
            {
                _mutexes = new List<Mutex>() { new Mutex(a, b), new Mutex(b, a), };
                a.onVideoWillPlay.AddListener(OnWillPlay);
                a.onVideoPlayComplete.AddListener(OnPlayComplete);
                b.onVideoWillPlay.AddListener(OnWillPlay);
                b.onVideoPlayComplete.AddListener(OnPlayComplete);
                return;
            }
            bool hasA = _mutexes.Find(m => m.A == a) != null;
            bool hasB = _mutexes.Find(m => m.B == b) != null;
            if (!hasA)
            {
                a.onVideoWillPlay.AddListener(OnWillPlay);
                a.onVideoPlayComplete.AddListener(OnPlayComplete);
            }
            if (!hasB)
            {
                b.onVideoWillPlay.AddListener(OnWillPlay);
                b.onVideoPlayComplete.AddListener(OnPlayComplete);
            }
            bool addAb = true;
            bool addBa = true;
            foreach (var m in _mutexes)
            {
                if (m.A == a && m.B == b)
                {
                    addAb = false;
                }
                else if (m.A == b && m.B == a)
                {
                    addBa = false;
                }
            }
            if (addAb)
            {
                _mutexes.Add(new Mutex(a, b));
            }
            if (addBa)
            {
                _mutexes.Add(new Mutex(b, a));
            }
        }
    }
}
